package com.jltx.zeus.viewmodel

import kotlinx.coroutines.*
import kotlinx.coroutines.channels.ProducerScope
import kotlinx.coroutines.channels.ReceiveChannel
import kotlinx.coroutines.channels.produce
import kotlin.coroutines.CoroutineContext
import kotlin.coroutines.EmptyCoroutineContext

/**
 * @author jltxseo
 *         Created by junlintianxia on 2020/05/10.
 */
interface CoroutineEvent {
    val viewModelScope: CoroutineScope

    //此字段用于声明在全局范围下的协程作用域，不和生命周期绑定
    val globalScope: CoroutineScope
        get() = GlobalScope

    fun launch(
        coroutineScope: CoroutineScope,
        context: CoroutineContext = EmptyCoroutineContext,
        block: suspend CoroutineScope.() -> Unit
    ): Job {
        return coroutineScope.launch(context) {
            block()
        }
    }

    fun launch(
        context: CoroutineContext = EmptyCoroutineContext,
        block: suspend CoroutineScope.() -> Unit
    ): Job {
        return viewModelScope.launch(context) {
            block()
        }
    }

    fun <T> async(
        coroutineScope: CoroutineScope,
        context: CoroutineContext = EmptyCoroutineContext,
        block: suspend CoroutineScope.() -> T
    ): Deferred<T> {
        return coroutineScope.async(context) {
            block()
        }
    }

    fun <T> async(
        context: CoroutineContext = EmptyCoroutineContext,
        block: suspend CoroutineScope.() -> T
    ): Deferred<T> {
        return viewModelScope.async(context) {
            block()
        }
    }

    fun <T> produce(
        coroutineScope: CoroutineScope,
        context: CoroutineContext = EmptyCoroutineContext,
        capacity: Int = 0,
        block: suspend ProducerScope<T>.() -> Unit
    ): ReceiveChannel<T> {
        return coroutineScope.produce(context) {
            block()
        }
    }

    fun <T> produce(
        context: CoroutineContext = EmptyCoroutineContext,
        capacity: Int = 0,
        block: suspend ProducerScope<T>.() -> Unit
    ): ReceiveChannel<T> {
        return viewModelScope.produce(context) {
            block()
        }
    }

    suspend fun <T> withMain(block: suspend CoroutineScope.() -> T): T =
        withContext(Dispatchers.Main) {
            block()
        }

    suspend fun <T> withIO(block: suspend CoroutineScope.() -> T): T =
        withContext(Dispatchers.IO) {
            block()
        }

    suspend fun <T> withCPU(block: suspend CoroutineScope.() -> T): T =
        withContext(Dispatchers.Default) {
            block()
        }

    //用于在 UI 线程完成操作
    fun launchUI(block: suspend CoroutineScope.() -> Unit): Job {
        return launch(Dispatchers.Main, block)
    }

    //用于完成 CPU 密集型的操作
    fun launchCPU(block: suspend CoroutineScope.() -> Unit): Job {
        return launch(Dispatchers.Default, block)
    }

    //用于在 IO 密集型的操作
    fun launchIO(block: suspend CoroutineScope.() -> Unit): Job {
        return launch(Dispatchers.IO, block)
    }

    //用于在 UI 线程完成操作
    fun <T> asyncUI(block: suspend CoroutineScope.() -> T): Deferred<T> {
        return async(Dispatchers.Main, block)
    }

    //用于完成 CPU 密集型的操作
    fun <T> asyncCPU(block: suspend CoroutineScope.() -> T): Deferred<T> {
        return async(Dispatchers.Default, block)
    }

    //用于在 IO 密集型的操作
    fun <T> asyncIO(block: suspend CoroutineScope.() -> T): Deferred<T> {
        return async(Dispatchers.IO, block)
    }


    //用于在 UI 线程完成操作
    fun launchUIGlobal(block: suspend CoroutineScope.() -> Unit): Job {
        return launch(globalScope, Dispatchers.Main, block)
    }

    //用于完成 CPU 密集型的操作
    fun launchCPUGlobal(block: suspend CoroutineScope.() -> Unit): Job {
        return launch(globalScope, Dispatchers.Default, block)
    }

    //用于在 IO 密集型的操作
    fun launchIOGlobal(block: suspend CoroutineScope.() -> Unit): Job {
        return launch(globalScope, Dispatchers.IO, block)
    }

    //用于在 UI 线程完成操作
    fun <T> asyncUIGlobal(block: suspend CoroutineScope.() -> T): Deferred<T> {
        return async(globalScope, Dispatchers.Main, block)
    }

    //用于完成 CPU 密集型的操作
    fun <T> asyncCPUGlobal(block: suspend CoroutineScope.() -> T): Deferred<T> {
        return async(globalScope, Dispatchers.Default, block)
    }

    //用于在 IO 密集型的操作
    fun <T> asyncIOGlobal(block: suspend CoroutineScope.() -> T): Deferred<T> {
        return async(globalScope, Dispatchers.IO, block)
    }
}